﻿using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace EasyComm.Hosting.NLB
{
    public class SynchronizedDictionary<TKey, TValue>
    //where TKey : class
    //where TValue : class
    {
        public enum AddOrUpdateStatus
        {
            Added,
            Updated,
            Unchanged
        };

        private ReaderWriterLockSlim _innerLock = new ReaderWriterLockSlim();
        private Dictionary<TKey, TValue> _innerDictionary = new Dictionary<TKey, TValue>();

        public SynchronizedDictionary()
        {
            
        }

        public TValue Read(TKey key)
        {
            _innerLock.EnterReadLock();
            try
            {
                return _innerDictionary[key];
            }
            finally
            {
                _innerLock.ExitReadLock();
            }
        }

        public void Add(TKey key, TValue value)
        {
            _innerLock.EnterWriteLock();
            try
            {
                _innerDictionary.Add(key, value);
            }
            finally
            {
                _innerLock.ExitWriteLock();
            }
        }

        public bool AddWithTimeout(TKey key, TValue value, int timeout)
        {
            if (_innerLock.TryEnterWriteLock(timeout))
            {
                try
                {
                    _innerDictionary.Add(key, value);
                }
                finally
                {
                    _innerLock.ExitWriteLock();
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        public AddOrUpdateStatus AddOrUpdate(TKey key, TValue value)
        {
            _innerLock.EnterUpgradeableReadLock();
            try
            {
                TValue result = default(TValue);
                if (_innerDictionary.TryGetValue(key, out result))
                {
                    if (result.Equals(value))
                    {
                        return AddOrUpdateStatus.Unchanged;
                    }
                    else
                    {
                        _innerLock.EnterWriteLock();
                        try
                        {
                            _innerDictionary[key] = value;
                        }
                        finally
                        {
                            _innerLock.ExitWriteLock();
                        }
                        return AddOrUpdateStatus.Updated;
                    }
                }
                else
                {
                    _innerLock.EnterWriteLock();
                    try
                    {
                        _innerDictionary.Add(key, value);
                    }
                    finally
                    {
                        _innerLock.ExitWriteLock();
                    }
                    return AddOrUpdateStatus.Added;
                }
            }
            finally
            {
                _innerLock.ExitUpgradeableReadLock();
            }
        }

        public void Delete(TKey key)
        {
            _innerLock.EnterWriteLock();
            try
            {
                _innerDictionary.Remove(key);
            }
            finally
            {
                _innerLock.ExitWriteLock();
            }
        }

        public List<TValue> GetSortedValues()
        {
            return GetSortedValues(null);
        }

        public List<TValue> GetSortedValues(IComparer<TValue> comparer)
        {
            _innerLock.EnterReadLock();
            try
            {
                List<TValue> sortedValues = _innerDictionary.Values.ToList();
                if (comparer != null)
                {
                    sortedValues.Sort(comparer);
                }
                else
                {
                    sortedValues.Sort();
                }
                return sortedValues;
            }
            finally
            {
                _innerLock.ExitReadLock();
            }
        }
    }
}
